﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Discovery;
using Microsoft.Crm.Sdk.Messages;
using System.Windows;
using System.ServiceModel.Description;
using System.Windows.Controls;
using System.Collections.ObjectModel;
using System.Security.Principal;

namespace Email_Validator
{
    public class crmauthinfo : DependencyObject
    {
        private String _discoveryServiceAddress;

        public String DiscoveryServiceAddress
        {
            get { return _discoveryServiceAddress; }
            set { _discoveryServiceAddress = value; }
        }

        private String _organizationUniqueName;

        public String OrganizationUniqueName
        {
            get { return _organizationUniqueName; }
            set { _organizationUniqueName = value; }
        }

        private String _userName;

        public string UserName
        {
            get { return _userName; }
            set { _userName = value; }
        }

        private String _password;

        public string Password
        {
            get { return _password; }
            set { _password = value; }
        }

        private String _domain;

        public string Domain
        {
            get { return _domain; }
            set { _domain = value; }
        }

        private DiscoveryServiceProxy _discoproxy;

        public DiscoveryServiceProxy DiscoProxy
        {
            get { return _discoproxy; }
            set { _discoproxy = value; }
        }

        private bool _useCurrentCreds;

        public bool UseCurrentCreds
        {
            get { return _useCurrentCreds; }
            set { _useCurrentCreds = value; }
        }

        public ComboBox Orgbox;

        public OrganizationDetail OrgDetail
        {
            get { return _orgDetail; }
            set { _orgDetail = value; }
        }

        private OrganizationDetail _orgDetail;
       
        public OrganizationServiceProxy CrmService
        {
            get { return _crmService; }
            set { _crmService = value; }
        }

        private OrganizationServiceProxy _crmService;

        public bool IsQueue
        {
            get { return _isQueue; }
            set { _isQueue = value; }
        }

        private bool _isQueue;

        public string QueueAddress
        {
            get { return _queueAddress; }
            set { _queueAddress = value; }
        }

        private string _queueAddress;

      public string TargetMailbox
        {
            get { return _targetMailbox; }
            set { _targetMailbox = value; }
        }

        private string _targetMailbox;

        public crmauthinfo(string discoaddress, string username, string password, string domain, ComboBox orgbox, bool queue, string queueaddress)
        {
            DiscoveryServiceAddress = discoaddress;
            UserName = username;
            Password = password;
            Domain = domain;
            Orgbox = orgbox;
            IsQueue = queue;
            QueueAddress = queueaddress;
        }

        public void Run()
        {
            IServiceManagement<IDiscoveryService> serviceManagement =
                        ServiceConfigurationFactory.CreateManagement<IDiscoveryService>(
                        new Uri(_discoveryServiceAddress));
            AuthenticationProviderType endpointType = serviceManagement.AuthenticationType;

            AuthenticationCredentials authCredentials = GetCredentials(serviceManagement, endpointType);

            if (authCredentials.ClientCredentials.Windows.ClientCredential.UserName == null)
            {
                MessageBox.Show("The Windows.ClientCredential.Username parameter was null.", "Error");
                return;
            }

            String organizationUri = String.Empty;
            // Get the discovery service proxy.
            using (DiscoProxy = GetProxy<IDiscoveryService, DiscoveryServiceProxy>(serviceManagement, authCredentials))
            {
                // Obtain organization information from the Discovery service. 
                if (DiscoProxy != null)
                {
                    // Obtain information about the organizations that the system user belongs to.
                    OrganizationDetailCollection orgs = DiscoverOrganizations(DiscoProxy);
                    ObservableCollection<OrganizationDetail> list = new ObservableCollection<OrganizationDetail>();  
                    foreach (var org in orgs)
                    {
                        list.Add(org);
                    }
                    Orgbox.ItemsSource = list;
                    Orgbox.SelectedItem = Orgbox.Items[0];
                }
            }

        }

        public OrganizationDetailCollection DiscoverOrganizations(
         IDiscoveryService service)
        {
            if (service == null) throw new ArgumentNullException("service");
            RetrieveOrganizationsRequest orgRequest = new RetrieveOrganizationsRequest();
            RetrieveOrganizationsResponse orgResponse =
                (RetrieveOrganizationsResponse)service.Execute(orgRequest);

            return orgResponse.Details;
        }


        private AuthenticationCredentials GetCredentials<TService>(IServiceManagement<TService> service, AuthenticationProviderType endpointType)
        {
            AuthenticationCredentials authCredentials = new AuthenticationCredentials();

            if (UseCurrentCreds)
            {
                UserName = System.Net.CredentialCache.DefaultNetworkCredentials.UserName;
                Password = System.Net.CredentialCache.DefaultNetworkCredentials.Password;
                Domain = System.Net.CredentialCache.DefaultNetworkCredentials.Domain;

                if (string.IsNullOrEmpty(UserName))
                {
                    MessageBox.Show("Default credential information is missing. This error can occur if you have selected \"Use Current Credentials\" but are not logged onto a domain.");
                    return authCredentials;
                }
            }

            switch (endpointType)
            {
                case AuthenticationProviderType.ActiveDirectory:
                    authCredentials.ClientCredentials.Windows.ClientCredential =
                        new System.Net.NetworkCredential(_userName,
                            _password,
                            _domain);
                    break;
                case AuthenticationProviderType.LiveId:
                    authCredentials.ClientCredentials.UserName.UserName = _userName;
                    authCredentials.ClientCredentials.UserName.Password = _password;
                    authCredentials.SupportingCredentials = new AuthenticationCredentials();
                    authCredentials.SupportingCredentials.ClientCredentials =
                        Microsoft.Crm.Services.Utility.DeviceIdManager.LoadOrRegisterDevice();
                    break;
                default: // For Federated and OnlineFederated environments.                    
                    authCredentials.ClientCredentials.UserName.UserName = _userName;
                    authCredentials.ClientCredentials.UserName.Password = _password;
                    // For OnlineFederated single-sign on, you could just use current UserPrincipalName instead of passing user name and password.
                    // authCredentials.UserPrincipalName = UserPrincipal.Current.UserPrincipalName;  // Windows Kerberos

                    // The service is configured for User Id authentication, but the user might provide Microsoft
                    // account credentials. If so, the supporting credentials must contain the device credentials.
                    if (endpointType == AuthenticationProviderType.OnlineFederation)
                    {
                        IdentityProvider provider = service.GetIdentityProvider(authCredentials.ClientCredentials.UserName.UserName);
                        if (provider != null && provider.IdentityProviderType == IdentityProviderType.LiveId)
                        {
                            authCredentials.SupportingCredentials = new AuthenticationCredentials();
                            authCredentials.SupportingCredentials.ClientCredentials =
                                Microsoft.Crm.Services.Utility.DeviceIdManager.LoadOrRegisterDevice();
                        }
                    }

                    break;
            }

            return authCredentials;
        }

        private TProxy GetProxy<TService, TProxy>(
           IServiceManagement<TService> serviceManagement,
           AuthenticationCredentials authCredentials)
           where TService : class
           where TProxy : ServiceProxy<TService>
        {
            Type classType = typeof(TProxy);

            if (serviceManagement.AuthenticationType !=
                AuthenticationProviderType.ActiveDirectory)
            {
                AuthenticationCredentials tokenCredentials =
                    serviceManagement.Authenticate(authCredentials);
                // Obtain discovery/organization service proxy for Federated, LiveId and OnlineFederated environments. 
                // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and SecurityTokenResponse.
                return (TProxy)classType
                    .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(SecurityTokenResponse) })
                    .Invoke(new object[] { serviceManagement, tokenCredentials.SecurityTokenResponse });
            }

            // Obtain discovery/organization service proxy for ActiveDirectory environment.
            // Instantiate a new class of type using the 2 parameter constructor of type IServiceManagement and ClientCredentials.
            return (TProxy)classType
                .GetConstructor(new Type[] { typeof(IServiceManagement<TService>), typeof(ClientCredentials) })
                .Invoke(new object[] { serviceManagement, authCredentials.ClientCredentials });
        }

        public void GetOrgProxy(OrganizationDetail organizationDetail)
        {
            IServiceManagement<IOrganizationService> orgServiceManagement = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(organizationDetail.Endpoints[EndpointType.OrganizationService].ToString()));
            IServiceManagement<IDiscoveryService> serviceManagement = ServiceConfigurationFactory.CreateManagement<IDiscoveryService>(new Uri(_discoveryServiceAddress));
            AuthenticationProviderType endpointType = serviceManagement.AuthenticationType;
            AuthenticationCredentials credentials = GetCredentials(orgServiceManagement, endpointType);
            CrmService = GetProxy<IOrganizationService, OrganizationServiceProxy>(orgServiceManagement, credentials);
        }

    }


}
